/*
 * @Author: lll 1280388921@qq.com
 * @Date: 2025-06-14 00:37:36
 * @LastEditors: lll 1280388921@qq.com
 * @LastEditTime: 2025-06-20 00:29:24
 * @FilePath: /lesson42/2.tcp/TcpServer.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstdlib>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <pthread.h>
#include "log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include"Daemon.hpp"

using namespace std;

const int defaultfd = -1;
const string defaultip = "0.0.0.0";
const int backlog = 5; // 一般不要设置的太大


enum
{
    UsageError = 1,
    CreateError,
    BindError,
    ListenError
};

class TcpServer;

class ThreadData
{
public:
    ThreadData(int fd, string ip, uint16_t port, TcpServer *t)
        : sockfd(fd), clientip(ip), clientport(port), tsvr(t)
    {
    }

public:
    int sockfd;
    string clientip;
    uint16_t clientport;
    TcpServer *tsvr;
};

class TcpServer
{
public:
    TcpServer(const uint16_t &port, const string &ip = defaultip)
        : listenfd_(defaultfd), port_(port), ip_(ip)
    {
    }
    void InitServer()
    {
        listenfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd_ < 0)
        {
            lg(Fatal, "Create listenfd Error,errno: %d , strerrno: %s ", errno, strerror(errno));
            exit(CreateError);
        }
        lg(Info, "create listenfd success,listenfd: %d ", listenfd_);

        int opt=1;
        setsockopt(listenfd_,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));//防止偶发性的服务器无法立即重启

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        inet_aton(ip_.c_str(), &(local.sin_addr));
        // local.sin_addr.s_addr=INADDR_ANY;

        if (bind(listenfd_, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            lg(Fatal, "Bind Error,errno: %d , strerrno: %s ", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "Bind sockfd success,listenfd: %d ", listenfd_);

        // tcp是面向连接的，服务器一般是比较“被动的”。
        // 服务器一般是比较“被动的”，服务器一直是处于一种等待连接到来的状态
        if (listen(listenfd_, backlog) < 0)
        {
            lg(Fatal, "Listen Error,errno: %d , strerrno: %s ", errno, strerror(errno));
            exit(ListenError);
        }
        lg(Info, "Listen success,listenfd: %d ", listenfd_);
    }
    static void *Routine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->tsvr->Service(td->sockfd, td->clientip, td->clientport);
        delete td;
        return nullptr;
    }
    void Start()
    {
        // signal(SIGPIPE,SIG_IGN);//读端关闭 写端进程可能被杀掉
        Daemon();
        ThreadPool<Task>::GetInstance()->Start();
        // 整个进程for fork也可以【就可以使用单进程版本了】 但是要对linstensockfd加锁！
        //  signal(SIGCHLD,SIG_IGN);
        lg(Info, "tcpServer is running...");
        for (;;)
        {
            // 1.获取新连接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(listenfd_, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                lg(Warming, "accept Error,errno: %d , strerrno: %s ", errno, strerror(errno));
                continue;
            }
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));

            lg(Info, "accept success , get a new link...sockfd: %d , clientip: %s ,clientport: %d ", sockfd, clientip, clientport);

            // 2.根据新连接进行通信

            // version 1 -- 单进程版
            // Service(sockfd, clientip, clientport);
            // close(sockfd);
            // 只能给一个用户提供服务（只有但一个用户结束才能进行下一个）

            // version 2  -- 多进程版
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     // child
            //     close(listenfd_);
            //     if (fork() > 0)
            //         exit(0);                           // 子进程自己退了
            //     Service(sockfd, clientip, clientport); // 孙子进程进行提供服务 被系统领养
            //     close(sockfd);
            //     exit(0);
            // }
            // // father
            // close(sockfd);
            // pid_t rid = waitpid(id, nullptr, 0); // 也可以设置为非阻塞等待
            // // 子进程退出立马返回
            // (void)rid;
            // 来一个新连接，才创建子（孙子）进程，而且子（孙子）进程会越来越多【进程池版】
            // 创建进程的成本高！

            // version 3 -- 多线程版
            // ThreadData*td=new ThreadData(sockfd,clientip,clientport,this);
            // pthread_t tid;
            // pthread_create(&tid,nullptr,Routine,td);
            // 如果突然有很多连接 那么创建的线程就会变得很多

            // version 4 -- 线程池版
            Task t(sockfd, clientip, clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }
    void Service(const int &sockfd, const string &clientip, const uint16_t &clientport)
    {
        char buffer[4096];
        while (1)
        {
            ssize_t n = read(sockfd, buffer, sizeof(buffer));
            if (n > 0)
            {
                buffer[n] = 0;
                cout << "client say: " << buffer << endl;

                string echo_string = "server echo: ";
                echo_string += buffer;
                write(sockfd, echo_string.c_str(), echo_string.size());
            }
            else if (n == 0)
            {
                lg(Info, "%s : %d quit!close sockfd : %d ", clientip.c_str(), clientport, sockfd);
                break;
            }
            else
            {
                lg(Warming, "read error ,sockfd: %d ,clientip: %s ,clientport: %d", sockfd, clientip.c_str(), clientport);
                break;
            }
        }
    }
    ~TcpServer() {}

private:
    int listenfd_;
    uint16_t port_;
    string ip_;
};